package org.nativejpa;

import org.nativejpa.query.NamedSQLTemplate;
import org.nativejpa.query.SQLTemplate;
import org.nativejpa.query.QueryExt;
import org.nativejpa.query.SQLQuery;
import org.nativejpa.query.CacheQuerySynchronization;
import org.nativejpa.query.TransactionQuerySynchronization;
import org.nativejpa.query.ConnectionQuerySynchronization;
import org.nativejpa.query.NamedQueryNotFoundException;
import org.nativejpa.transaction.EntityTransactionImpl;
import org.nativejpa.mapping.MappingEntity;

import javax.persistence.Query;
import javax.persistence.EntityTransaction;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

/**
 * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
 * @create 2009-3-18 13:38:07
 */
public class EntityManagerImpl extends EntityManagerExt {

    private static final Log logger = LogFactory.getLog(EntityManagerImpl.class);

    public EntityManagerImpl(EntityManagerFactoryImpl emFactory) {
        super(emFactory);
        if (!getEntityManagerFactory().getEntityManagerFactoryBuilder().isContainerManaged()) {
            this.registerQuerySynchronization(new TransactionQuerySynchronization());
        }
        this.registerQuerySynchronization(new CacheQuerySynchronization());
        this.registerQuerySynchronization(new ConnectionQuerySynchronization());
    }

    /**
     * Returns the resource-level transaction object.
     * The EntityTransaction instance may be used serially to
     * begin and commit multiple transactions.
     *
     * @return EntityTransaction instance
     * @throws IllegalStateException if invoked on a JTA
     *                               EntityManager.
     */
    public EntityTransaction getTransaction() {
        checkClosed();
        if (getEntityManagerFactory().getEntityManagerFactoryBuilder().isContainerManaged()) {
            throw new IllegalArgumentException("Can not call EntityManager.getTransaction() on Container Managed JTA EntityManager.");
        }
        else {
            return this.getEntityManagerFactory().getEntityTransaction();
        }
    }

    //use joinTransaction to Join JTA Transaction if you want to collaboration the second EntityManager with current one
    public void joinTransaction() {
        checkClosed();
        if (getEntityManagerFactory().getEntityManagerFactoryBuilder().isContainerManaged()) {
            throw new IllegalArgumentException("Can not call EntityManager.joinTransaction() on Container Managed JTA EntityManager.");
        }
        else {
            ((EntityTransactionImpl)getTransaction()).joinTransaction();
        }
    }

    public void suspendTransaction() {
        checkClosed();
        if (getEntityManagerFactory().getEntityManagerFactoryBuilder().isContainerManaged()) {
            throw new IllegalArgumentException("Can not call EntityManager.joinTransaction() on Container Managed JTA EntityManager.");
        }
        else {
            ((EntityTransactionImpl)getTransaction()).suspendTransaction();
        }
    }

    public void resumeTransaction() {
        checkClosed();
        if (getEntityManagerFactory().getEntityManagerFactoryBuilder().isContainerManaged()) {
            throw new IllegalArgumentException("Can not call EntityManager.joinTransaction() on Container Managed JTA EntityManager.");
        }
        else {
            ((EntityTransactionImpl)getTransaction()).resumeTransaction();
        }
    }
}
